use chrono::{FixedOffset, NaiveDateTime};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};

pub fn read_file(path: &str) -> String {
    // read file
    // return string
    let contents = std::fs::read_to_string(path).expect("Something went wrong reading the file");
    contents
} 

pub fn write_file(path: &str, content: &str) {
    std::fs::write(path, content).expect("Something went wrong writing the file");
}

pub fn sub_string(str: &str, start: usize, end: usize) -> String {
    let (sidx, _) = str.char_indices().nth(start).unwrap();
    let (eidx, _) = str.char_indices().nth(end).unwrap();
    if start == 0 {
        return str.get(..eidx).unwrap().to_owned()
    }
    if end == 0 {
        return str.get(sidx..).unwrap().to_owned()
    }
    str.get(sidx..eidx).unwrap().to_owned()
}

pub fn short_id() -> String {
    let alphabet: [char; 16] = [
        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f'
    ];

    nanoid!(10, &alphabet)
}

pub fn str_to_timestamp(datetime_str: &str, format: &str) -> i64 {
    let naive_datetime = NaiveDateTime::parse_from_str(datetime_str, format).expect("解析失败");
    let sec = naive_datetime.and_local_timezone(FixedOffset::east_opt(8 * 3600).unwrap()).unwrap().timestamp();
    sec
}


pub fn generate_random_string(length: usize) -> String {
    let alphabet: Vec<char> = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".chars().collect();

    nanoid!(length, &alphabet)
}
pub fn generate_random_numeric_string(length: usize) -> String {
    let alphabet: Vec<char> = "0123456789".chars().collect();

    nanoid!(length, &alphabet)
}


pub fn parse_xml<'de, T>(xml: &'de str) -> T 
where
    T: Deserialize<'de>,
{
    let doc = quick_xml::de::from_str(xml).unwrap();
    doc
}

pub fn to_xml<T>(value: &T) -> String 
where
    T: ?Sized + Serialize,
{
    quick_xml::se::to_string(value).unwrap()
}


#[cfg(test)]
mod tests {
    use serde::Deserialize;
    use serde_json::Value;

    use super::*;

    #[test]
    fn test_sub_string() {
        let str = "Hello, world!";
        let result = sub_string(str, 7, 12);
        assert_eq!(result, "world");
    }

    #[test]
    fn test_short_id() {
        let result = short_id();
        println!("{}", result);
        assert_eq!(result.len(), 10);
    }

    #[test]
    fn test_parse_xml() {
        let xml = "<xml><ToUserName><![CDATA[gh_41b1c4d52b1c]]></ToUserName><FromUserName><![CDATA[oIWsFt0gFiIjYvR8g5PxFvR6V61U]]></FromUserName><CreateTime>1723456789</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[Hello]]></Content><MsgId>1234567890</MsgId></xml>";
        let result: Value = parse_xml(xml);
        assert_eq!(result["ToUserName"]["$text"], "gh_41b1c4d52b1c");
        assert_eq!(result["FromUserName"]["$text"], "oIWsFt0gFiIjYvR8g5PxFvR6V61U");
        assert_eq!(result["CreateTime"]["$text"], "1723456789");
        assert_eq!(result["MsgType"]["$text"], "text");
        assert_eq!(result["Content"]["$text"], "Hello");
        assert_eq!(result["MsgId"]["$text"], "1234567890");

        #[derive(Debug, Deserialize)]
        struct TestStruct {
            #[serde(rename = "ToUserName")]
            to_user_name: String,
            #[serde(rename = "FromUserName")]
            from_user_name: String,
        }
        let result: TestStruct = quick_xml::de::from_str(xml).unwrap();
        assert_eq!(result.to_user_name, "gh_41b1c4d52b1c");
        assert_eq!(result.from_user_name, "oIWsFt0gFiIjYvR8g5PxFvR6V61U");
    }
}